﻿// ============================================================================
//  _ __   ___  ___  ___ _ __ ___  _   _
// | '_ \ / _ \/ __|/ _ \ '_ ` _ \| | | |
// | | | |  __/\__ \  __/ | | | | | |_| |
// |_| |_|\___||___/\___|_| |_| |_|\__,_|
//
// NES Emulator by daxnet, 2024
// MIT License
// ============================================================================

using System;
using System.Drawing;
using System.IO;
using System.Runtime.CompilerServices;
using System.Windows.Forms;
using Krypton.Navigator;
using NesEmu.Core.Rendering;
using NesEmu.Explorer.Properties;

namespace NesEmu.Explorer.Pages;

public partial class ChrRomViewerPage : UserControl
{

    #region Private Fields

    private readonly FrmMain? _parent;

    private readonly FileBrowserPage.FileBrowserItemTag? _tag;
    private int _bmpHeight;
    private int _bmpWidth;
    private float _factor = 1.5f;
    private readonly Renderer _renderer = new Renderer();

    #endregion Private Fields

    #region Public Constructors

    public ChrRomViewerPage(FrmMain parent, FileBrowserPage.FileBrowserItemTag tag)
                : this()
    {
        _parent = parent;
        _tag = tag;
    }

    #endregion Public Constructors

    #region Private Constructors

    private ChrRomViewerPage()
    {
        InitializeComponent();
    }

    #endregion Private Constructors

    #region Protected Methods

    protected override void OnLoad(EventArgs e)
    {
        base.OnLoad(e);
        tcbBanks.Items.Clear();
        if (_tag?.Cartridge is not null && _tag.Cartridge?.ChrRomBanks > 0)
        {
            for (var i = 0; i < _tag.Cartridge.ChrRomBanks; i++)
            {
                tcbBanks.Items.Add(i);
            }

            tcbBanks.SelectedIndex = 0;
        }
    }

    #endregion Protected Methods

    #region Private Methods

    private void RenderBank(int bank, Palette palette)
    {
        if (_tag?.Cartridge is null)
            return;

        // Tiles each bank
        var tilesEachBank = _tag.Cartridge.ChrRomSize / (_tag.Cartridge.ChrRomBanks * 16);

        var bmp = new Bitmap(128, tilesEachBank / 2);


        for (var i = 0; i < tilesEachBank; i++)
        {
            var currentTileIndex = i;
            _renderer.RenderCartridgeChrRomBank(_tag.Cartridge, bank, i, palette, v => v switch
            {
                0 => 0x01,
                1 => 0x23,
                2 => 0x27,
                3 => 0x30,
                _ => 0,
            }, (x, y, colorRgb) =>
            {
                var pixel = Color.FromArgb(255, colorRgb.R, colorRgb.G, colorRgb.B);
                var tileX = currentTileIndex % 16;
                var tileY = currentTileIndex / 16;
                bmp.SetPixel(tileX * 8 + x, tileY * 8 + y, pixel);
            });
        }

        pictureBox.Image = bmp;
        _bmpWidth = bmp.Width;
        _bmpHeight = bmp.Height;
        tcbZoom.SelectedIndex = 2;
    }
    private void tcbBanks_SelectedIndexChanged(object sender, EventArgs e)
    {
        var bankNumber = Convert.ToInt32(tcbBanks.SelectedItem);
        RenderBank(bankNumber, Palette.Default);
    }

    private void tcbZoom_SelectedIndexChanged(object sender, EventArgs e)
    {
        _factor = tcbZoom.SelectedIndex switch
        {
            0 => 1.0f,
            1 => 1.2f,
            2 => 1.5f,
            3 => 2.0f,
            _ => 1.0f
        };

        Zoom();
    }

    private void Zoom()
    {
        pictureBox.Width = Convert.ToInt32(_bmpWidth * _factor);
        pictureBox.Height = Convert.ToInt32(_bmpHeight * _factor);
    }

    #endregion Private Methods

    #region Public Classes

    public sealed class Page : KryptonPage
    {

        #region Public Fields

        public const string PageName = @"87BB05B8-8008-4BEE-A7B1-83ACED0CFDCE";

        #endregion Public Fields

        #region Private Fields

        private readonly ChrRomViewerPage _ctrl;

        #endregion Private Fields

        #region Public Constructors

        public Page(FrmMain parent, object? args = null)
        {
            if (args is not FileBrowserPage.FileBrowserItemTag selectedNesFile)
                throw new ArgumentException(@"Selected node doesn't have NES file information.", nameof(args));

            Text = @$"CHR Viewer - {Path.GetFileName(selectedNesFile.FilePath)}";
            TextTitle = Text;
            TextDescription = Text;
            ImageSmall = Resources.ImageListControl_683;

            if (selectedNesFile.Cartridge is null) throw new InvalidOperationException("Cartridge is empty.");

            _ctrl = new ChrRomViewerPage(parent, selectedNesFile)
            {
                Dock = DockStyle.Fill
            };

            Controls.Add(_ctrl);
        }

        #endregion Public Constructors

    }

    #endregion Public Classes
}